#ifdef __linux__
#ifndef HASIO_DETAIL_SCHEDULER_HPP
#define HASIO_DETAIL_SCHEDULER_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "op_queue.hpp"
#include "reactor_fwd.hpp"
#include "scheduler_operation.hpp"
#include <thread>

// ipp
#include "reactor.hpp"

namespace hasio {
namespace detail {

class scheduler
{
public:
    scheduler()
        : stopped_(false)
        , worker_(nullptr)
        , thread_(nullptr)
    {
        // TODO
        // thread_ = new std::thread([this]() {
        //     this->run();
        // });
    }

    ~scheduler()
    {
        if (thread_)
        {
            if (thread_->joinable())
            {
                thread_->join();
            }
            delete thread_;
        }
    }

    using operation = scheduler_operation;

public:
    void init_task()
    {
        if (!worker_)
        {
            worker_ = new reactor();
            op_que_.push(&task_op_);
        }
    }

    std::size_t run()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        std::size_t n = 0;
        for (; do_run_once(); )
        {
            ++n;
        }
        return n;
    }

    void post_operation(operation* op)
    {
        op_que_.push(op);
    }

private:
    std::size_t do_run_once()
    {
        while (!stopped_)
        {
            if (!op_que_.empty())
            {
                operation* op = op_que_.front();
                op_que_.pop();

                if (op == &task_op_)
                {
                    op_queue<operation> ops;
                    worker_->run(ops);
                }
                else
                {
                    op->complete();
                    return 1;
                }
            }
            else
            {

            }
        }
        return 0;
    }

private:
    bool stopped_;
    class task_op
        : public operation
    {
    public:
        task_op() : operation(nullptr) {}
    } task_op_;
    op_queue<operation> op_que_;
    reactor* worker_;
    std::thread* thread_;
    mutable std::mutex mutex_;
};

}
}

#endif // HASIO_DETAIL_SCHEDULER_HPP
#endif